#pragma once 
#include <string>
#include <unordered_map>
#include <fstream>
#include <boost/algorithm/string.hpp>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>


//提供的编译版本，一般我们就是用c++11
std::unordered_map<int, std::string> CppStandard = {
    {98, "-std=c++98"}, 
    {11, "-std=c++11"},
    {14, "-std=c++14"},
    {17, "-std=c++17"},
    {20, "-std=c++20"},
};


class PathUtil{
private:
    static const std::string tmp_path;

    static std::string AddSuffix(const std::string& name, const std::string& suffix){
        std::string ret = PathUtil::tmp_path;
        ret += name;
        ret += suffix;
        return ret;
    }

public:
    //这里是编译源文件的时候所需要的
    static std::string Src(const std::string& name){return AddSuffix(name, ".cpp");}                    //生成被编译的源文件
    static std::string Exe(const std::string& name){return AddSuffix(name, ".exe");}                    //生成被编译的可执行文件
    static std::string Compile_err(const std::string& name){return AddSuffix(name, ".compile_err");}    //出现错误，就需要把错误信息重定向到一个专门的文件

    //这里是运行文件的时候所需要的(其实就是标准输入输出错误流 重定向的文件)
    static std::string Stdin(const std::string& name){return AddSuffix(name, ".stdin");}                //stdin的重定向文件
    static std::string Stdout(const std::string& name){return AddSuffix(name, ".stdout");}              //stdout的重定向文件
    static std::string Stderr(const std::string& name){return AddSuffix(name, ".stderr");}                //stderr的重定向文件
};

const std::string PathUtil::tmp_path = "./temp/";   //我觉得应该是用绝对路径 但是这里先不管了，先将就用着



class FileUtil{
public:
    //给出一个文件的完整路径，进行判断该文件是否存在
    static bool IsFileExist(const std::string& file_path){
        struct stat st;
        int n = stat(file_path.c_str(), &st);
        return (n == 0);
    }

    //把文本写入到指定文件
    static bool WriteIntoFile(const std::string& target, const std::string& content){
        std::ofstream out(target);
        if(!out.is_open()) return false;
        out.write(content.c_str(), content.size());
        out.close();
        return true;
    }

    //后序还可能需要读
    static bool ReadFromFile(const std::string& target, std::string* content, bool is_keep = false){
        (*content).clear(); //强制清空一下，方便操作

        std::ifstream in(target);
        if(!in.is_open()) return false;

        std::string line;
        //这里有两个问题：
        //1.我们使用getline是比较方便的，但是要注意，它会自动舍弃"\n"
        //2.判断条件我们不需要担心，getline内部做了重载的，我们直接把它放在循环条件即可，只要没数据自动就退出循环了
        while(std::getline(in, line)){
            (*content) += line;
            (*content) += (is_keep ? "\n" : "");
        }
        in.close();
        return true;
    }
};


class TimeUtil{
public:
    //获取秒级时间戳
    static int GetTimeStamp(){
        struct timeval tv;
        int t = gettimeofday(&tv, nullptr);
        return tv.tv_sec;
    }

    //获取毫秒级时间戳
    static int GetTimeStamp_ms(){
        struct timeval tv;
        int t = gettimeofday(&tv, nullptr);
        return tv.tv_sec * 1000 + tv.tv_usec / 1000;
    }
};


class StringUtil{
public:
    static void StringSplit(const std::string& src, std::vector<std::string>* tokens, const std::string& sep){
        boost::split(*tokens, src, boost::is_any_of(sep), boost::token_compress_on);
    }
};